﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Media;
using System.Drawing.Drawing2D;
using System.Diagnostics;
using System.IO;
using System.Xml;

namespace GPCodeConjurer
{
	public partial class Form1 : Form
	{
		public Form1()
		{
			InitializeComponent();

			this.lineJoinType.Text = "Miter";
			this.graphicsPathEditor1.IndicationColor = Color.FromArgb(255, Color.Red);
			this.graphicsPathEditor1.SelectionChanged += (o, ev) =>
			{
				this.listBox1.SelectedItem = this.graphicsPathEditor1.SelectedNode;
				var n = this.graphicsPathEditor1.SelectedNode;
				this.chkStartFigureSel.Checked = (n != null && n.StartFigure);
				this.chkCloseFigureSel.Checked = (n != null && n.CloseFigure);

				this.RefreshPropertyControls(n);

			};
			this.graphicsPathEditor1.NodeRemoved += (o, ev) =>
			{
				this.listBox1.Items.Remove(ev.Node);
			};
			this.graphicsPathEditor1.NodeAdded += (o, ev) =>
			{
				this.btnAddArc.Checked = false;
				this.btnAddLine.Checked = false;
				this.btnAddEllipse.Checked = false;

				this.listBox1.Items.Insert(this.graphicsPathEditor1.Nodes.IndexOf(ev.Node), ev.Node);
			};
			this.graphicsPathEditor1.SelectedNodePropertyChanged += (o, ev) =>
			{
				var node = ev.Node;
				this.RefreshPropertyControls(node);
			};
			this.graphicsPathEditor1.NodeListCleared += (o, ev) =>
				{
					this.listBox1.Items.Clear();
				};

			this.openFileDialog1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
			this.saveFileDialog1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
			this.saveImageDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
		}

		private void button1_Click(object sender, EventArgs e)
		{
			Random r = new Random();
			Point pt1 = new Point(
			r.Next(this.graphicsPathEditor1.Width),
			r.Next(this.graphicsPathEditor1.Height));
			Point pt2 = new Point(
			r.Next(this.graphicsPathEditor1.Width),
			r.Next(this.graphicsPathEditor1.Height));

			this.graphicsPathEditor1.AddNode(new Line(pt1, pt2) { StartFigure = this.btnStartFigure.Checked, CloseFigure = this.btnCloseFigure.Checked, });
		}

		private void button2_Click(object sender, EventArgs e)
		{
			using (var form = new CodeWindow(this.graphicsPathEditor1.CreateCode()))
			{
				form.ShowDialog();
			}
		}


		private void RenderNodeList()
		{
			this.listBox1.Items.Clear();
			foreach (var node in this.graphicsPathEditor1.Nodes)
			{
				this.listBox1.Items.Add(node);
			}
			this.listBox1.SelectedItem = this.graphicsPathEditor1.SelectedNode;
		}

		private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
		{
			Node node = this.listBox1.SelectedItem as Node;
			if (node != null)
			{
				node.Selected = true;
			}
		}

		private void chkStartFigureSel_CheckedChanged(object sender, EventArgs e)
		{
			Node node = this.listBox1.SelectedItem as Node;
			if (node != null)
			{
				node.StartFigure = this.chkStartFigureSel.Checked;
			}
		}

		private void chkCloseFigureSel_CheckedChanged(object sender, EventArgs e)
		{
			Node node = this.listBox1.SelectedItem as Node;
			if (node != null)
			{
				node.CloseFigure = this.chkCloseFigureSel.Checked;
			}
		}

		private void button5_Click(object sender, EventArgs e)
		{

		}

		private void button6_Click(object sender, EventArgs e)
		{

		}

		private void txtArcStartAngle_TextChanged(object sender, EventArgs e)
		{
			var arc = this.graphicsPathEditor1.SelectedNode as Arc;
			if (arc != null)
			{
				float f = arc.StartAngle;
				if (float.TryParse(this.txtArcStartAngle.Text, out f))
				{
					arc.StartAngle = f;
					//this.txtArcStartAngle.Text = arc.StartAngle.ToString();
					//this.trackBar1.Value = Convert.ToInt32(f) % 360;
					//this.graphicsPathEditor1.Invalidate();
				}
			}
		}

		private void txtArcSweepAngle_TextChanged(object sender, EventArgs e)
		{
			var arc = this.graphicsPathEditor1.SelectedNode as Arc;
			if (arc != null)
			{
				float f = arc.SweepAngle;
				if (float.TryParse(this.txtArcSweepAngle.Text, out f))
				{
					arc.SweepAngle = f;
					//this.txtArcSweepAngle.Text = arc.SweepAngle.ToString();
					//this.trackBar2.Value = Convert.ToInt32(f) % 360;
					//this.graphicsPathEditor1.Invalidate();
				}
			}
		}



		private void trackBar1_ValueChanged(object sender, EventArgs e)
		{
			var arc = this.graphicsPathEditor1.SelectedNode as Arc;
			if (arc != null)
				arc.StartAngle = this.trackBar1.Value;
		}

		private void trackBar2_ValueChanged(object sender, EventArgs e)
		{
			var arc = this.graphicsPathEditor1.SelectedNode as Arc;
			if (arc != null)
				arc.SweepAngle = this.trackBar2.Value;
		}

		private void button7_Click(object sender, EventArgs e)
		{
			Node n = this.listBox1.SelectedItem as Node;
			if (n != null)
			{
				this.graphicsPathEditor1.RemoveNode(n);
			}
		}

		private void chkFillPath_CheckedChanged(object sender, EventArgs e)
		{
			this.graphicsPathEditor1.FillPath = this.btnFillPath.Checked;
			this.graphicsPathEditor1.Invalidate();
		}

		private void txtLineWidth_TextChanged(object sender, EventArgs e)
		{
			float f = this.graphicsPathEditor1.LineWidth;
			if (float.TryParse(this.txtLineWidth.Text, out f))
			{
				this.graphicsPathEditor1.LineWidth = f;
				this.graphicsPathEditor1.Invalidate();
			}
		}


		private void newToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.graphicsPathEditor1.Clear();
			this.listBox1.Items.Clear();
		}

		private void toolStripButton1_Click(object sender, EventArgs e)
		{
			this.New();
		}

		private void fillModeButton_CheckedChanged(object sender, EventArgs e)
		{
			this.fillModeButton.Text = (this.fillModeButton.Checked) ? "Fill mode: Alternate" : "Fill mode: Winding";
			this.graphicsPathEditor1.FillMode = (this.fillModeButton.Checked) ? FillMode.Alternate : FillMode.Winding;
			this.graphicsPathEditor1.Invalidate();
		}

		private void moveNodeUpButton_Click(object sender, EventArgs e)
		{
			var node = this.listBox1.SelectedItem as Node;
			if (node != null)
			{
				int i = this.graphicsPathEditor1.Nodes.IndexOf(node);
				if (i > -1 && i > 0)
				{
					this.graphicsPathEditor1.Nodes.Remove(node);
					this.graphicsPathEditor1.Nodes.Insert(i - 1, node);
					this.graphicsPathEditor1.Invalidate();
					this.RenderNodeList();
				}
			}
		}

		private void moveNodeDownButton_Click(object sender, EventArgs e)
		{
			var node = this.listBox1.SelectedItem as Node;
			if (node != null)
			{
				int i = this.graphicsPathEditor1.Nodes.IndexOf(node);
				if (i > -1 && i < this.graphicsPathEditor1.Nodes.Count - 1)
				{
					this.graphicsPathEditor1.Nodes.Remove(node);
					this.graphicsPathEditor1.Nodes.Insert(i + 1, node);
					this.graphicsPathEditor1.Invalidate();
					this.RenderNodeList();
				}
			}
		}



		private void lineJoinType_SelectedIndexChanged(object sender, EventArgs e)
		{
			this.graphicsPathEditor1.LineJoin = (LineJoin)Enum.Parse(typeof(LineJoin), this.lineJoinType.Text, true);
			this.graphicsPathEditor1.Invalidate();
		}

		private void indicateObjectsButton_CheckedChanged(object sender, EventArgs e)
		{
			this.graphicsPathEditor1.IndicateObjects = this.indicateObjectsButton.Checked;
			this.graphicsPathEditor1.Invalidate();
		}




		private void ChargeEditor(Node node)
		{
			this.graphicsPathEditor1.DrawNode = node;

			this.btnAddArc.Checked = (node is Arc);
			this.btnAddLine.Checked = (node is Line);
			this.btnAddEllipse.Checked = (node is Ellipse);


		}

		private void btnAddLine_Click(object sender, EventArgs e)
		{
			Random r = new Random();
			Point pt1 = new Point(
			r.Next(this.graphicsPathEditor1.Width),
			r.Next(this.graphicsPathEditor1.Height));
			Point pt2 = new Point(
			r.Next(this.graphicsPathEditor1.Width),
			r.Next(this.graphicsPathEditor1.Height));
			var node = new Line(pt1, pt2) { StartFigure = this.btnStartFigure.Checked, CloseFigure = this.btnCloseFigure.Checked, };

			((ToolStripButton)sender).Checked = true;

			this.ChargeEditor(node);
		}

		private void btnAddEllipse_Click(object sender, EventArgs e)
		{
			Random r = new Random();
			RectangleF rect = new RectangleF(
			r.Next(this.graphicsPathEditor1.Width),
			r.Next(this.graphicsPathEditor1.Height),
			r.Next(30, 60),
			r.Next(30, 60));
			var node = new Ellipse(rect) { StartFigure = this.btnStartFigure.Checked, CloseFigure = this.btnCloseFigure.Checked, };

			((ToolStripButton)sender).Checked = true;

			this.ChargeEditor(node);
		}

		private void btnAddArc_Click(object sender, EventArgs e)
		{
			Random r = new Random();
			RectangleF rect = new RectangleF(
			r.Next(this.graphicsPathEditor1.Width),
			r.Next(this.graphicsPathEditor1.Height),
			r.Next(30, 60),
			r.Next(30, 60));
			var node = new Arc(rect, Convert.ToSingle(r.NextDouble() * 300 + 60), Convert.ToSingle(r.NextDouble() * 300 + 60)) { StartFigure = this.btnStartFigure.Checked, CloseFigure = this.btnCloseFigure.Checked, };

			((ToolStripButton)sender).Checked = true;

			this.ChargeEditor(node);
		}

		private void toolStripButton2_Click(object sender, EventArgs e)
		{
			this.ChargeEditor(null);
		}



		private void RefreshPropertyControls(Node n)
		{
			this.groupBox1.Visible = (n is Arc);
			//Debug.WriteLineIf((n is Arc), ((Arc)n).StartAngle.ToString());
			if (n is Arc)
			{
				this.txtArcStartAngle.Text = ((Arc)n).StartAngle.ToString("##0.00");
				this.txtArcSweepAngle.Text = ((Arc)n).SweepAngle.ToString("##0.00");
				this.trackBar1.Value = Convert.ToInt32(((Arc)n).StartAngle);
				this.trackBar2.Value = Convert.ToInt32(((Arc)n).SweepAngle);
			}
		}

		private void txtArcStartAngle_Enter(object sender, EventArgs e)
		{
			this.txtArcStartAngle.Leave += this.txtArcStartAngle_TextChanged;
		}

		private void txtArcStartAngle_Leave(object sender, EventArgs e)
		{
			this.txtArcStartAngle.Leave -= this.txtArcStartAngle_TextChanged;
		}

		private void txtArcSweepAngle_Enter(object sender, EventArgs e)
		{
			this.txtArcSweepAngle.Leave += this.txtArcSweepAngle_TextChanged;
		}

		private void txtArcSweepAngle_Leave(object sender, EventArgs e)
		{
			this.txtArcSweepAngle.Leave -= this.txtArcSweepAngle_TextChanged;
		}

		private void trackBar1_Enter(object sender, EventArgs e)
		{
			this.trackBar1.ValueChanged += this.trackBar1_ValueChanged;
		}

		private void trackBar1_Leave(object sender, EventArgs e)
		{
			this.trackBar1.ValueChanged -= this.trackBar1_ValueChanged;
		}

		private void trackBar2_Enter(object sender, EventArgs e)
		{
			this.trackBar2.ValueChanged += this.trackBar2_ValueChanged;

		}

		private void trackBar2_Leave(object sender, EventArgs e)
		{
			this.trackBar2.ValueChanged -= this.trackBar2_ValueChanged;
		}

		private void btnZoomOut_Click(object sender, EventArgs e)
		{
			this.graphicsPathEditor1.Zoom /= 1.25f;
			this.lblZoomFactorText.Text = string.Format("{0:##0}%", this.graphicsPathEditor1.Zoom * 100);
		}

		private void btnZoomIn_Click(object sender, EventArgs e)
		{
			this.graphicsPathEditor1.Zoom *= 1.25f;
			this.lblZoomFactorText.Text = string.Format("{0:##0}%", this.graphicsPathEditor1.Zoom * 100);
		}


		public string openedFilePath = string.Empty;



		internal void New()
		{
			var r = MessageBox.Show("Save changes?", "GraphicsPath Code Conjurer", MessageBoxButtons.YesNoCancel);
			if (r == DialogResult.Cancel)
				return;
			if (r == DialogResult.Yes)
				this.Save();

			this.graphicsPathEditor1.Clear();
			this.listBox1.Items.Clear();
		}


		internal void Open()
		{
			var r = MessageBox.Show("Save changes?", "GraphicsPath Code Conjurer", MessageBoxButtons.YesNoCancel);
			if (r == DialogResult.Cancel)
				return;
			if (r == DialogResult.Yes)
				this.Save();


			if (this.openFileDialog1.ShowDialog() == DialogResult.OK)
			{
				XmlDocument xmlDoc = new XmlDocument();
				xmlDoc.Load(this.openFileDialog1.OpenFile());
				this.graphicsPathEditor1.Deserialize(xmlDoc);
				this.openedFilePath = this.openFileDialog1.FileName;
				this.openFileDialog1.FileName = "";
				this.saveFileDialog1.InitialDirectory = Path.GetDirectoryName(this.openedFilePath);
			}

		}



		internal void Save()
		{
			if (string.IsNullOrEmpty(this.openedFilePath))
			{
				this.SaveAs();
				return;
			}

			var xmlDoc = this.graphicsPathEditor1.Serialize();
			xmlDoc.Save(this.openedFilePath);
			this.saveFileDialog1.FileName = "";
			this.openFileDialog1.InitialDirectory = Path.GetDirectoryName(this.openedFilePath);
			this.openFileDialog1.InitialDirectory = Path.GetDirectoryName(this.openedFilePath);
		}


		internal void SaveAs()
		{
			if (this.saveFileDialog1.ShowDialog() == DialogResult.OK)
			{
				this.openedFilePath = this.saveFileDialog1.FileName;
				this.Save();
			}
		}




		private void toolStripButton2_Click_1(object sender, EventArgs e)
		{
			this.Open();
		}

		private void btnSave_Click(object sender, EventArgs e)
		{
			this.Save();
		}

		private void btnSaveAsImage_Click(object sender, EventArgs e)
		{
			if (this.saveImageDialog.ShowDialog() == DialogResult.OK)
			{
				using (var img = this.graphicsPathEditor1.ExportToImage())
				{
					img.Save(this.saveImageDialog.FileName);
				}
				this.saveImageDialog.FileName = "";
			}
		}



	}
}
